/*****************************************************************************************
 *                                     TinyRtos51
 *                                The Real-Time Kernel
 *                              Copyright(c) 2024 fanxsp
 *                         SPDX-License-Identifier: APACHE-2.0
 *       This software is subject to an open source license and is distributed by fanxsp,
 *       pursuant to the terms of the Apache License.
 ******************************************************************************************/
/*******************************************************************************************
 * 				main.c文件
 * Author: fanxsp
 * Revision: 1.00
 * Date: 2023-05-03
 * 	1. 在tinyrtos51cfg.h 中配置 OS
 *   2. 在port.h port_xxx.h中适配不同型号的 MCU
 *   3. 在option的c51中的预定义宏中定义目标MCU型号
 *   4. 如果使能定时服务，需要在一个定时器中调用OSTimeTick()函数，定时中断应设为最低优先级
 ********************************************************************************************/

/*************  功能说明    ****************************************************************
 * 本例程基于STC8H8K64U核心实验板（开天斧）进行编写测试。
 * 程序演示跑马灯效果，输出低驱动LED。
 * 下载时, 选择时钟 24MHZ (用户可自行修改频率)。
 * 按键P32 循环改变跑马灯的频率
 * 测试目的：任务切换、任务挂起、任务恢复、任务延时
 ********************************************************************************************/
#include "tinyrtos51.h"

#define MAIN_Fosc 24000000L
#define Timer0_Reload (65536UL - (MAIN_Fosc / 1000)) // Timer0 中断频率 1000次/秒

/* 任务定义 -------------------------------------------------------------------------------*/
/* 任务堆栈  */
OStypeInt8u OSLOC_STACKS taskStack0[30];
OStypeInt8u OSLOC_STACKS taskStack1[30];
/* 任务ID  */
#define ID_TASK0 0
#define ID_TASK1 1
/* 任务优先级 */
#define PRIO_TASK0 5
#define PRIO_TASK1 6
/* 任务函数原型 */
void Task0(void *p_arg);
void Task1(void *p_arg);

void ISR_Timer0(void) __interrupt 1;
/*-----------------------------------------------------------------------------------------*/

#define KEY1 1
#define KEY2 2
#define KEY3 3

void Init(void);
unsigned char t = 2;
unsigned char mode = 0;
unsigned char oldKey = 0;

void main(void)
{
    /* OS初始化  */
    OSInit();

    /* 创建任务、二值信号量、计数信号量、事件标志、消息队列  放在这里 */
    OSCreateTask(ID_TASK0, Task0, taskStack0, PRIO_TASK0);
    OSCreateTask(ID_TASK1, Task1, taskStack1, PRIO_TASK1);

    /*----------------------------------------------------------------------------------------*/

    /* 用户初始化 放在这里  */
    Init();
    /*----------------------------------------------------------------------------------------*/

    /* 启动OS */
    OSStart();
}

/* LED控制任务  */
void Task0(void *p_arg)
{
    p_arg;
    for (;;)
    {
        if (mode == 1)
        {
            P35 = 0;    // LED On
            OSDelay(t); // 任务延时
            P35 = 1;    // LED Off
            P36 = 0;    // LED On
            OSDelay(t);
            P36 = 1; // LED Off
            P37 = 0; // LED On
            OSDelay(t);
            P37 = 1; // LED Off
        }
        else if (mode == 2)
        {
            P37 = 0;
            OSDelay(t); // 任务延时
            P37 = 1;
            P36 = 0; // LED On
            OSDelay(t);
            P36 = 1;    // LED Off
            P35 = 0;    // LED On
            OSDelay(t); // 任务延时
            P35 = 1;    // LED Off
        }
        else
        {
            P35 = 0;
            P36 = 0;
            P37 = 0;
            OSDelay(t); // 任务延时
            P35 = 1;
            P36 = 1;
            P37 = 1;
            OSDelay(t); // 任务延时
        }
    }
}

/* 按键检测 任务 */
void Task1(void *p_arg)
{
    p_arg;
    static unsigned char Key1Cnt;
    unsigned char newKey;
    for (;;)
    {
        if (!P64 || !P65 || !P66)
        {
            if (!P64)
            {
                newKey = KEY1;
            }
            else if (!P65)
            {
                newKey = KEY2;
            }
            else
            {
                newKey = KEY3;
            }

            if (oldKey != newKey)
            {
                Key1Cnt = 1;
                oldKey = newKey;
            }

            if (Key1Cnt < 0xff)
                Key1Cnt++;
        }
        else
        {
            Key1Cnt = 0;
        }

        if (Key1Cnt == 250)
        {
            OSEnterCritical();
            mode = newKey;
            OSExitCritical();
        }

        OSTaskSuspend(); // 任务挂起
    }
}

void ISR_Timer0(void) __interrupt 1 // 1ms 中断函数
{
    OSIntResume(ID_TASK1); // 恢复任务
    OSTimeTick();          // OS节拍处理
}

void Init(void)
{
    P_SW2 |= 0x80; // 扩展寄存器(XFR)访问使能
    P0M1 = 0x00;
    P0M0 = 0x00; // 设置为准双向口
    P1M1 = 0x00;
    P1M0 = 0x00; // 设置为准双向口
    P2M1 = 0x00;
    P2M0 = 0x00; // 设置为准双向口
    P3M1 = 0x00;
    P3M0 = 0x00; // 设置为准双向口
    P4M1 = 0x00;
    P4M0 = 0x00; // 设置为准双向口
    P5M1 = 0x00;
    P5M0 = 0x00; // 设置为准双向口
    P6M1 = 0x00;
    P6M0 = 0x00; // 设置为准双向口
    P7M1 = 0x00;
    P7M0 = 0x00; // 设置为准双向口

    AUXR = 0x80; // Timer0 1T, 16 bits 自动重装载模式
    TH0 = (unsigned char)(Timer0_Reload / 256);
    TL0 = (unsigned char)(Timer0_Reload % 256);
    ET0 = 1; // Timer0 中断使能
    TR0 = 1; // Tiner0 开
}
